/** @file    Notification.cpp
 *  @author  Alessandro Polo
 *  @version $Id: Notification.cpp 2833 2010-08-02 23:12:57Z alex $
 *  @brief
 * File containing methods for the wosh::Notification class.
 * The header for this class can be found in Notification.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/
 
 #include <core/Notification.h>

 #include <core/ObjectAllocator.h>
 #include <core/DataModels.h>
 #include <core/Message.h>


using namespace std;
namespace wosh {

 WOSH_REGISTER_INTERFACE(wosh::Notification, "wosh::MessageContent", 1.01, _static_Notification)

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

Notification::Notification()
	: MessageContent() {
	clear();
 }

Notification::Notification( const Notification& m )
	: MessageContent( (const MessageContent&)m ) {
	clear();
	*this = m;
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////// CONFIGURATION

void Notification::clear() {
	this->flow_uid = 0;
	this->uid = Utilities::randomLong();
	this->uid = _GET_Abs(this->uid);
	this->timestamp = Utilities::std_time();

	this->sender_id = "";
	this->sender_user = "";
	this->recipent_id = "";
	this->recipent_user = "";
	this->recipent_group = "";

	this->language = "en_GB";

	this->protocol = Notification::PROTOCOL_UNKNOWN;
	this->priority = Notification::PRIORITY_UNKNOWN;

	this->read_timestamp = 0;
	this->sent_timestamp = 0;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Notification::setTimeStamp() {
	this->timestamp = Utilities::std_time();
 }

void Notification::setRead( bool value, long epoch ) {
	if ( value ) {
		if ( epoch == 0 )
			this->read_timestamp = Utilities::std_time();
		else
			this->read_timestamp = epoch;
	 }
	else
		this->read_timestamp = 0;
 }

void Notification::setSent( bool value, long epoch ) {
	if ( value ) {
		if ( epoch == 0 )
			this->sent_timestamp = Utilities::std_time();
		else
			this->sent_timestamp = epoch;
	 }
	else
		this->sent_timestamp = 0;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

Notification& Notification::operator=( const Notification& m ) {
	if (this == &m) return *this; // same object?

	this->flow_uid = m.flow_uid;
	this->uid = m.uid;
	this->timestamp = m.timestamp;

	this->sender_id = m.sender_id;
	this->sender_user = m.sender_user;
	this->recipent_id = m.recipent_id;
	this->recipent_user = m.recipent_user;
	this->recipent_group = m.recipent_group;

	this->protocol = m.protocol;
	this->priority = m.priority;

	this->read_timestamp = m.read_timestamp;
	this->sent_timestamp = m.sent_timestamp;

	return *this;
 }

bool Notification::operator==( const Notification &other ) const {
	if ( this->uid != other.uid )
		return false;

	return true;
 }

int Notification::compare( const ISerializable* other ) const {
	// bugs, be compliant!
	if ( other == NULL || !other->isKindOf<Notification>() )
		return -1;
	const Notification* notif = dynamic_cast<const Notification*>(other);
	if ( !this->sender_id.empty() && this->sender_id != notif->sender_id )
		return 2;
	if ( !this->sender_user.empty() && this->sender_user != notif->sender_user )
		return 3;
	if ( !this->recipent_id.empty() && this->recipent_id != notif->recipent_id )
		return 4;
	if ( !this->recipent_user.empty() && this->recipent_user != notif->recipent_user )
		return 5;
	if ( !this->recipent_group.empty() && this->recipent_group != notif->recipent_group )
		return 6;
	return 0;
 }

//////////////////////////////////////////////////////////////////////////////////////////////// DEBUG & INFO
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

DataFieldCollector<Notification>* Notification::getDataFields() {
	DataFieldCollector<Notification>* fields = new DataFieldCollector<Notification>();
	fields->add<long,Variant>(&Notification::getID, "ID", 0);
	fields->add<long,Variant>(&Notification::getFlowID, "FlowID", 1);
	fields->add<long,Variant_DT>(&Notification::getTimeStamp, "TimeStamp", 2);
	fields->add<long,Variant_DT>(&Notification::getSentTimeStamp, "SentTimeStamp", 3);
	fields->add<long,Variant_DT>(&Notification::getReadTimeStamp, "ReadTimeStamp", 4);
	fields->add<const std::string&, Variant>(&Notification::getSender_ID, "Sender UserID", 5);
	fields->add<const std::string&, Variant>(&Notification::getSender_User, "Sender User", 6);
	fields->add<const std::string&, Variant>(&Notification::getRecipent_ID, "Recipent UserID", 7);
	fields->add<const std::string&, Variant>(&Notification::getRecipent_User, "Recipent User", 8);
	fields->add<const std::string&, Variant>(&Notification::getLanguage, "Language", 9);
	fields->add<const URI&, URI>(&Notification::getPreferredCommunicator, "PreferredCommunicator", 10);
	fields->add<Notification::PRIORITY,Variant>(&Notification::getPriority, "Priority", 11, false);
	fields->add<Notification::PROTOCOL,Variant>(&Notification::getProtocol, "Protocol", 12, false);
	return fields;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////// SERIALIZATION

std::string Notification::toString() const {
	return Utilities::format("%s#%ld[for %s]", getClassNameOnlyOf(getClassName()), this->uid, this->recipent_user.c_str() );
 }

bool Notification::updateHash( DataHashContext* hash_context ) const {
	if ( hash_context == NULL ) return false;
	bool ret = true;
	ret = hash_context->update( this->uid ) & ret;
	ret = hash_context->update( this->flow_uid ) & ret;
	ret = hash_context->update( this->timestamp ) & ret;
	ret = hash_context->update( this->priority ) & ret;
	ret = hash_context->update( this->sender_id ) & ret;
	ret = hash_context->update( this->sender_user ) & ret;
	ret = hash_context->update( this->recipent_id ) & ret;
	ret = hash_context->update( this->recipent_user ) & ret;
	ret = hash_context->update( this->recipent_group ) & ret;
	ret = hash_context->update( this->read_timestamp ) & ret;
	ret = hash_context->update( this->sent_timestamp ) & ret;
	ret = hash_context->update( this->protocol ) & ret;
	ret = hash_context->update( this->language ) & ret;
	ret = this->preferredComm.updateHash( hash_context ) & ret;
	return ret;
 }

/////////////////////////////////////////////////////////////////////////////////////////////// SERIALIZATION
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

const char* Notification::getPriorityAsString( Notification::PRIORITY priority ) {
	switch(priority) {
		case Notification::PRIORITY_LOW:		return "LOW";
		case Notification::PRIORITY_DEFAULT:	return "DEFAULT";
		case Notification::PRIORITY_HIGH:		return "HIGH";
		case Notification::PRIORITY_REALTIME:	return "REALTIME";
		case Notification::PRIORITY_UNKNOWN:
		default:								return "UNKNOWN";
	 }
 }

const char* Notification::getProtocolAsString( Notification::PROTOCOL protocol ) {
	switch(protocol) {
		case Notification::PROTOCOL_SHELL:		return "SHELL";
		case Notification::PROTOCOL_HUMAN:		return "HUMAN";
		case Notification::PROTOCOL_UNKNOWN:
		default:								return "UNKNOWN";
	 }
 }

const char* Notification::getNotificationTypeAsString( Notification::TYPE type ) {
	switch(type) {
		case Notification::TYPE_TEXTUAL:		return "TEXTUAL";
		case Notification::TYPE_AUDIO:			return "AUDIO";
		case Notification::TYPE_VIDEO:			return "VIDEO";
		case Notification::TYPE_IMAGE:			return "IMAGE";
		case Notification::TYPE_DATA:			return "DATA";
		case Notification::TYPE_UNKNOWN:
		default:								return "UNKNOWN";
	 }
 }

std::string Notification::getTimeStampUTF() const {
	return Utilities::getTimeStampUTF(this->timestamp);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

};
